package qmt

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"quant/backend/api/dto"
	"quant/backend/constants"
	"quant/backend/utils"
	"strings"

	"github.com/duke-git/lancet/v2/slice"
	"github.com/sirupsen/logrus"
)

// GetStockCodeListBySector 获取沪深A股指定板块的所有股票代码列表
//
// 参数：
//
//	sector string - 需要查询的板块名称（需符合API要求的编码格式）
//
// 返回值：
//
//	[]string - 成功时返回股票代码字符串数组，格式为["600000.SH","300001.SZ"]等
//	error    - 失败时返回错误对象，包含具体的错误上下文信息
func GetStockCodeListBySector(sector string) ([]string, error) {
	// 构建符合miniQMT服务规范的API请求URL
	baseURL := constants.MiniQMTBaseUrl + "/get_stock_list_in_sector"
	params := url.Values{"sector": []string{sector}}
	fullURL := baseURL + "?" + params.Encode()

	// 发送带自动重试机制的HTTP GET请求
	resp, err := utils.HttpGet(fullURL, nil, nil)
	if err != nil {
		return nil, fmt.Errorf("HttpGet failed for sector %s: %w", sector, err)
	}
	defer func(Body io.ReadCloser) {
		_ = Body.Close()
	}(resp.Body)

	// 校验HTTP响应状态码（mys）
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("unexpected status code %d for sector %s", resp.StatusCode, sector)
	}

	// 读取完整的HTTP响应体内容
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("io.ReadAll failed for sector %s: %w", sector, err)
	}

	// 解析JSON格式的股票代码列表（预期为字符串数组格式）
	var codeList []string
	if err := json.Unmarshal(body, &codeList); err != nil {
		return nil, fmt.Errorf("json.Unmarshal failed for sector %s: %w", sector, err)
	}

	return codeList, nil
}

// GetDailyMarketData 获取当日行情数据
// 参数：
// strTime: 日期，格式为 YYYYMMDD
// strBody: 请求体，格式为 string, 股票代码列表，多个股票用英文逗号隔开
// 返回值：
func GetDailyMarketData(strTime, strBody string) (map[string]string, error) {
	var (
		resp *http.Response
		body []byte
		err  error
	)

	// 发送 HTTP 请求获取市场数据
	resp, err = utils.HttpPost(constants.MiniQMTBaseUrl+"/get_market_data/"+strTime, strBody, nil, nil)
	if err != nil {
		return nil, fmt.Errorf("getDailyMarketData(%s,[body]) -> HttpPost failed: %w", strTime, err)
	}
	defer func(Body io.ReadCloser) {
		_ = Body.Close()
	}(resp.Body) // 必须关闭响应体

	// 检查 HTTP 状态码是否为成功状态
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return nil, fmt.Errorf("getDailyMarketData(%s,[body]) -> unexpected status code: %d", strTime, resp.StatusCode)
	}

	// 读取响应体
	body, err = io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("getDailyMarketData(%s,[body]) -> io.ReadAll failed: %w", strTime, err)
	}

	// 解析 JSON 数据
	m := make(map[string]string)
	if err = json.Unmarshal(body, &m); err != nil {
		return nil, fmt.Errorf("getDailyMarketData(%s,[body]) -> json.Unmarshal failed: %w", strTime, err)
	}

	return m, nil
}

func GetDailyMarketData2(startTime, endTime, strBody string) (map[string]string, error) {
	var (
		resp *http.Response
		body []byte
		err  error
	)

	// 发送 HTTP 请求获取市场数据
	resp, err = utils.HttpPost(fmt.Sprintf("%s/get_market_data2/%s/%s", constants.MiniQMTBaseUrl, startTime, endTime), strBody, nil, nil)
	if err != nil {
		return nil, fmt.Errorf("GetDailyMarketData2 - HttpPost -> failed: %w", err)
	}
	defer func(Body io.ReadCloser) {
		_ = Body.Close()
	}(resp.Body) // 必须关闭响应体

	// 检查 HTTP 状态码是否为成功状态
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return nil, fmt.Errorf("GetDailyMarketData2 -> status_code: %d", resp.StatusCode)
	}

	// 读取响应体
	body, err = io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("GetDailyMarketData2 -> io.ReadAll failed: %w", err)
	}

	// 解析 JSON 数据
	m := make(map[string]string)
	if err = json.Unmarshal(body, &m); err != nil {
		return nil, fmt.Errorf("GetDailyMarketData2 -> json.Unmarshal failed: %w", err)
	}

	return m, nil
}

// Subscribe 订阅
func Subscribe(codeList []string) (string, error) {
	var (
		resp *http.Response
		body []byte
		err  error
	)
	slice.Join(codeList, ",")
	// 发送 HTTP 请求获取市场数据
	resp, err = utils.HttpPost(constants.MiniQMTBaseUrl+"/subscribe", slice.Join(codeList, ","), nil, nil)
	if err != nil {
		return "", fmt.Errorf("subscribe -> HttpPost failed: %w", err)
	}
	defer func(Body io.ReadCloser) {
		_ = Body.Close()
	}(resp.Body) // 必须关闭响应体

	// 检查 HTTP 状态码是否为成功状态
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return "", fmt.Errorf("subscribe -> unexpected status code: %d", resp.StatusCode)
	}

	// 读取响应体
	body, err = io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("subscribe -> io.ReadAll failed: %w", err)
	}

	return string(body), nil
}

// Unsubscribe 取消订阅
func Unsubscribe() (string, error) {
	var (
		resp *http.Response
		body []byte
		err  error
	)

	// 发送 HTTP 请求获取市场数据
	resp, err = utils.HttpGet(constants.MiniQMTBaseUrl+"/unsubscribe", nil, nil)
	if err != nil {
		return "", fmt.Errorf("unsubscribe -> HttpGet failed: %w", err)
	}
	defer func(Body io.ReadCloser) {
		_ = Body.Close()
	}(resp.Body) // 必须关闭响应体

	// 检查 HTTP 状态码是否为成功状态
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return "", fmt.Errorf("unsubscribe -> unexpected status code: %d", resp.StatusCode)
	}

	// 读取响应体
	body, err = io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("unsubscribe -> io.ReadAll failed: %w", err)
	}

	return string(body), nil
}

// GetTradingDates 获取指定日期到今天的交易日列表
// 参数：
// startDate: string 起始日期，格式为 YYYYMMDD
// 返回值：
//
//	[]string: 交易日列表
//	error: 错误信息
func GetTradingDates(startDate, endDate string) ([]string, error) {
	// 记录获取交易日列表的日志
	logrus.Infof("获取 %s 至今日的交易日列表", startDate)
	var arr []string

	// 发起HTTP GET请求获取交易日列表
	resp, err := utils.HttpGet(constants.MiniQMTBaseUrl+"/get_trading_dates/"+startDate+"/"+endDate, nil, nil)
	if err != nil {
		// 返回错误信息
		return arr, fmt.Errorf("getTradingDates->get_trading_dates 出现错误：%w", err)
	}
	defer func(Body io.ReadCloser) {
		_ = Body.Close()
	}(resp.Body)

	// 读取HTTP响应体
	body, err := io.ReadAll(resp.Body)
	// logrus.Info(string(body))
	if err != nil {
		// 返回读取响应体时的错误信息
		return arr, fmt.Errorf("getTradingDates->io.ReadAll 出现错误：%w", err)
	}
	strBody := string(body)

	// 移除JSON数组的括号和引号，以及换行符
	strBody = strings.Replace(strBody, "[", "", 1)
	strBody = strings.Replace(strBody, "]", "", 1)
	strBody = strings.Replace(strBody, "\"", "", -1)
	strBody = strings.Replace(strBody, "\n", "", -1)

	// 将处理后的字符串分割成交易日列表
	arr = strings.Split(strBody, ",")
	// sort.Sort(sort.Reverse(sort.StringSlice(arr)))
	// sort.Sort(sort.Reverse(sort.StringSlice(arr)))
	// 返回交易日列表
	return arr, nil
}

// GetInstrumentDetail 根据股票编码获取股票详情
func GetInstrumentDetail(stockCode string) (dto.InstrumentDto, error) {
	var instrumentDto dto.InstrumentDto
	resp, err := utils.HttpGet(constants.MiniQMTBaseUrl+"/get_instrument_detail/"+stockCode, nil, nil)
	if err != nil {
		return instrumentDto, fmt.Errorf("GetInstrumentDetail 出现错误：%w", err)
	}
	defer func(Body io.ReadCloser) {
		_ = Body.Close()
	}(resp.Body)

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return instrumentDto, fmt.Errorf("GetInstrumentDetail-> io.ReadAll 出现错误：%w", err)
	}

	if err = json.Unmarshal(body, &instrumentDto); err != nil {
		return instrumentDto, fmt.Errorf("GetInstrumentDetail -> json.Unmarshal 出现错误：%w", err)
	}
	return instrumentDto, nil
}
